/*
Source : https://leetcode.com/problems/max-points-on-a-line/
Author : nflush@outlook.com
Date   : 2016-07-06
*/

/*
149. Max Points on a Line

    Total Accepted: 59812
    Total Submissions: 409594
    Difficulty: Hard

Given n points on a 2D plane, find the maximum number of points that lie on the same straight line.

Subscribe to see which companies asked this question
*/

/**
 * Definition for a point.
 * struct Point {
 *     int x;
 *     int y;
 *     Point() : x(0), y(0) {}
 *     Point(int a, int b) : x(a), y(b) {}
 * };
 */
class Solution {
typedef struct {
    Point base;
    int k1;
    int k2; // k = k1/k2
}line;
private:
    int gcd(int a, int b){
        if(b == 0){
            return a;
        }
        return gcd(b, a % b);
    }
public:
    int maxPoints(vector<Point>& points) {
        int size = points.size();
        if(size <= 2){
            return size;
        }
        int ret = 0;
        vector<line>lines;
        vector<int>counts;
        line l;
        l.base = points[0];

        for(int i = 0; i < size; ++i){
            l.base = points[i];
            int x = points[i].x, y = points[i].y;
            for(int j = i + 1; j < size; ++j){
                int a = points[j].x - x, b = points[j].y - y;
                if(a == 0 && b == 0){
                    continue; //samepoint do nothing
                }else if(a == 0){
                    //vertical;
                    l.k1 = 1;
                    l.k2 = 0;
                }else{
                    int k = gcd(a, b);
                    l.k1 = a / k;
                    l.k2 = b / k;
                }
            }
        }

        return ret;
    }
};

class Solution {
public:
    // using map
    int maxPoints(vector<Point>& points) {
        int size = points.size();
        if(size <= 2){
            return size;
        }
        int maxNum = 0;
        for(int i = 0; i < size - 1; ++i){
            map<pair<int, int>, int> m;
            int samePoints = 0;
            int vertical = 0;
            int iMaxNum = 0;
            int x = points[i].x, y = points[i].y;
            for(int j = i + 1; j < size; ++j){
                int a = points[j].x - x, b = points[j].y - y;
                if(a == 0 && b == 0){
                    ++samePoints;
                }else if(a == 0){
                    ++vertical;
                    iMaxNum = max(iMaxNum, vertical);
                }else{
                    int k = gcd(a, b);
                    a /= k;
                    b /= k;
                    ++m[make_pair(a, b)];
                    iMaxNum = max(iMaxNum, m[make_pair(a, b)]);
                }
            }
            maxNum = max(maxNum, iMaxNum + samePoints + 1);
        }
        return maxNum;
    }
private:
    int gcd(int a, int b){
        if(b == 0){
            return a;
        }
        return gcd(b, a % b);
    }
};




// 8ms
class Solution {
private:
     static int compare(const void *a, const void *b)
     {
         if (*(float*)a<*(float*)b) return -1;
         if (*(float*)a>*(float*)b) return 1;
         return 0;
     }
    int getMaxkInMap(float *m, int s){
        qsort(m,s,sizeof(float),compare);
        int ret = 1;
        float tmp = m[0];
        int cur = 1;
        for(int i=1;i<s;i++){
            if (m[i] - tmp < 0.0001){
                cur++;
            } else {
                ret = max(ret, cur);
                cur = 1;
                tmp = m[i];
            }
        }
        return max(ret, cur);
    }
public:
    int maxPoints(vector<Point>& points) {
        int size = points.size();
        if(size <= 2){
            return size;
        }
        int maxNum = 0;
        // float *m = new float[size];
        float m[size];
        for(int i = 0; i < size - 1; ++i){
            int s = 0;
            int samePoints = 0;
            int vertical = 0;
            int iMaxNum = 0;
            int x = points[i].x, y = points[i].y;
            for(int j = i + 1; j < size; ++j){
                int a = points[j].x - x, b = points[j].y - y;
                if(a == 0 && b == 0){
                    ++samePoints;
                }else if(a == 0){
                    ++vertical;
                }else{
                    m[s++] = float(b)/float(a);
                }
            }
            if (s)
                iMaxNum = getMaxkInMap(m, s);
            maxNum = max(maxNum, max(iMaxNum, vertical) + samePoints + 1);
        }
        // delete [] m;
        return maxNum;
    }
};

